package the.workshop.bu.service;

import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.wisteria.framework.util.excel.ExcelUtil;
import org.wisteria.framework.web.BusinessException;
import the.broccoli.setting.service.IParamsService;
import the.workshop.bu.dto.CustomerImportExcel;
import the.workshop.bu.dto.req.CustomerTelAddReq;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import static the.broccoli.setting.constant.SettingConsts.FILE_UPLOAD_DIR;

/**
 * 客户数据导入、导出服务
 */
@Slf4j
@Service
public class CustomerImpExpService {

    @Resource
    private IParamsService paramsService;

    @Resource
    private ICustomerService customerService;

    @Async
    public void importExcelByAsync(String timeTag, String fileUrl) {
        //String filePath = "/Users/liul/deploy/upload/" + fileUrl;
        String uploadDir = paramsService.getValue(FILE_UPLOAD_DIR);
        String filePath = uploadDir + "/" + fileUrl;
        List<CustomerImportExcel> data = null;
        try {
            data = ExcelUtil.readXls(filePath, CustomerImportExcel.class);
            //data = ExcelUtil.readXls(file.getBytes(), CustomerImportExcel.class);
        } catch (Exception e) {
            log.error("导入客户数据，文件解析异常。fileUrl: {}, Msg: {}", fileUrl, e.getMessage());
            throw BusinessException.withErrorCode("导入客户数据，文件解析异常");
        }

        if (!CollectionUtils.isEmpty(data)) {
            log.info("导入客户数据，文件读取到数据共 {} 条，开始写入数据库。fileUrl: {}", data.size(), fileUrl);
            importExcel(timeTag, data);
        } else {
            log.info("导入客户数据，文件没有读取到数据。fileUrl: {}", fileUrl);
        }
    }

    @Async
    public void importExcelByAsync(List<CustomerImportExcel> data) {
        importExcel(null, data);
    }

    public void importExcel(String timeTag, List<CustomerImportExcel> data) {
        if (CollectionUtils.isEmpty(data)) {
            return;
        }

        Map<String, CustomerImportExcel> customerMap = new HashMap<>();
        CustomerImportExcel customer = null;
        CustomerTelAddReq telAddReq = null;
        for (CustomerImportExcel ce : data) {
            if (!StringUtils.hasText(ce.getName())) {
                continue;
            }

            ce.setTimeTag(timeTag);
            customer = customerMap.get(ce.getName());
            if (customer == null) {
                customer = ce;
                customerMap.put(ce.getName(), customer);
            }

            String telNumber = ce.getTelNumber();
            if (StringUtils.hasText(telNumber)) {
                String[] telNumberArray = null;
                int index = telNumber.indexOf(",");
                if (index > 0) {
                    telNumberArray = telNumber.split(",");
                } else {
                    index = telNumber.indexOf("，");
                    if (index > 0) {
                        telNumberArray = telNumber.split("，");
                    }
                }
                if (telNumberArray == null) {
                    telNumberArray = new String[] { telNumber };
                }

                for (String tel : telNumberArray) {
                    telAddReq = new CustomerTelAddReq();
                    telAddReq.setTelNumber(tel);
                    customer.getTels().add(telAddReq);
                }
            }
        }

        List<CustomerImportExcel> dataExcel = new ArrayList<>(customerMap.size());
        for (Map.Entry<String, CustomerImportExcel> entry : customerMap.entrySet()) {
            dataExcel.add(entry.getValue());
        }

        int pageSize = 900;
        int size = dataExcel.size();
        int count = 1;
        if (size > pageSize) {
            int num = size % pageSize;
            if (num > 0) {
                count = size / pageSize + 1;
            }
        } else {
            pageSize = size;
        }
        ExecutorService es = Executors.newCachedThreadPool();
        CountDownLatch doneSignal = new CountDownLatch(count);
        for (int i = 0; i < count; i++) {
            int from = i * pageSize;
            int to = from + pageSize;
            if (to > size) {
                to = size;
            }
            es.submit(new WriteRunnable(customerService, doneSignal, dataExcel.subList(from, to)));
        }

        try {
            doneSignal.await();
        } catch (Exception e) {
            log.error("导入客户失败.", e);
        } finally {
            es.shutdown();
        }

//        if (success) {
//            for (CustomerImportExcel excel : dataExcel) {
//                CustomerCache.saveName(excel.getName(), 1);
//            }
//        }
    }

    protected static class WriteRunnable implements Runnable {
        private ICustomerService customerService;
        private final CountDownLatch latch;
        private List<CustomerImportExcel> dataExcel;

        public WriteRunnable(ICustomerService customerService, CountDownLatch latch, List<CustomerImportExcel> dataExcel) {
            this.customerService = customerService;
            this.latch = latch;
            this.dataExcel = dataExcel;
        }

        @Override
        public void run() {
            try {
                customerService.save(dataExcel);
            } catch (Exception e) {
                log.error("客户批量导入，数据保存失败.", e);
            } finally {
                latch.countDown();
            }
        }
    }
}
